home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Magnum One
/
Magnum One (Mid-American Digital) (Disc Manufacturing).iso
/
d12
/
c_lib.arc
/
PCSETISR.C
< prev
next >
Wrap
Text File
|
1990-08-09
|
6KB
|
151 lines
/**
*
* Name pcsetisr -- Set interrupt service routine
*
* Synopsis ercode = pcsetisr(intype,pfunc,stksize,pvector,pisrblk);
* int ercode Error return code
* int intype Interrupt type number
* unsigned (*pfunc)() Pointer to interrupt service routine
* int stksize Stack size needed for ISR
* ADS *pvector Previous interrupt vector for the
* specified interrupt type.
* ISRCTRL **pisrblk Pointer to ISR control block
*
* Description pcsetisr sets the interrupt vector to point to an ISR
* control block. The control block is used by the ISR dis-
* patcher function to set up the ISR stack, call the actual
* ISR function and handle the interrupt protocol. The
* address of the control block is placed in the interrupt
* vector; the first bytes of the control block have the code
* necessary to invoke the ISR dispatcher. The control block
* is a structure, space for which is allocated on the heap,
* defined as follows:
*
* call instruction: The far call instruction starts with
* the opcode of 9A then the IP and CS values for the
* ISR dispatcher.
* ISR stack segment and pointer: The stack segment is set by
* PCISRSTK, and placed in variable external to PCSETISR.
* The stack pointer is the requested size of the stack.
* Data segment value of program setting up the ISR. The ISR
* will use the same data segment.
* Space to store the invoking programs stack segment and
* stack pointer. Because the ISR dispatcher must alter
* the stack, it must be restored before the interrupt
* service returns.
* Pointer to the C function which processes the interrupt,
* that is the Interrupt Service Routine (ISR).
*
* The original interrupt vector is returned so that it
* may be restored if the ISR is to be disabled, and a
* pointer to the control block is returned so space can be
* freed when it is no longer needed.
*
* Returns ercode The return code is 0 if the vector is
* is successfully set; other values are:
* 1 - Interrupt type out of range
* 2 - Cannot allocate space for ISR control
*
* Version 1.1 (C)Copyright Blaise Computing Inc. 1983, 1984
*
**/
#include <compiler.h>
#if LDATA
#define NULL 0L
#else
#define NULL 0
#endif
#define utoutrng(a,l,h) (((a)<(l)||(a)>(h))?1:0) /* Is a out of range? */
struct segads /* Offset, segment address type */
{
unsigned r;
unsigned s;
};
#define ADS struct segads /* Abbreviation */
struct isr_control
{
unsigned fcall_opcode; /* Far call op code 9A */
#if LPROG
int (*isrdisp)(); /* Pointer to ISR dispatcher */
#else
int (*isrdisp)();
unsigned isrdisp_cs; /* Code segment when it is NEAR */
#endif
unsigned isrss; /* ISR stack segment */
unsigned isrsp; /* ISR stack pointer */
unsigned isrstksize; /* ISR stack size */
unsigned isrds; /* ISR data segment */
unsigned savess; /* Location to save SS and SP */
unsigned savesp; /* from invoking program */
unsigned (*isr)(); /* Pointer to ISR. Note that */
}; /* 2 or 4 bytes depending on the*/
/* memory model used. */
#define ISRCTRL struct isr_control
extern unsigned isrss; /* ISR stack information from */
extern unsigned isrstk_base; /* PCSISRSTK. */
int pcsetisr(intype,pfunc,stksize,pvector,pisrblk)
int intype,stksize;
unsigned (*pfunc)();
ADS *pvector;
ISRCTRL **pisrblk;
{
ADS isrblk_ads;
char *calloc();
extern int invisr(); /* ISR dispatcher */
unsigned cs,ss,ds,es;
#if CI201A & LDATA
unsigned long ptrtoabs();
#endif
if (utoutrng(intype,0,255))
return(1);
pcretvec(intype,pvector); /* Return the interrupt vector */
*pisrblk = (ISRCTRL *)calloc(1,sizeof(ISRCTRL));
if (*pisrblk == NULL)
return(2);
utsreg(&cs,&ss,&ds,&es);
(*pisrblk)->fcall_opcode = 0x9a00;
#if LPROG
(*pisrblk)->isrdisp = invisr; /* ISR dispatcher address */
#else
(*pisrblk)->isrdisp = invisr;
(*pisrblk)->isrdisp_cs = cs;
#endif
(*pisrblk)->isrss = isrss; /* ISR stack segment and pointer */
(*pisrblk)->isrsp = isrstk_base + 2;
(*pisrblk)->isrstksize = stksize;
(*pisrblk)->isrds = ds; /* ISR data segment */
(*pisrblk)->isr = pfunc; /* Interrupt service routine */
/* Now load the interrupt vector with the segment and offset */
/* address of the ISR control block. */
#if LDATA
#if CI201A
isrblk_ads.s = (unsigned)((ptrtoabs(*pisrblk) & 0xffff0L) >> 4L);
isrblk_ads.r = (unsigned)(ptrtoabs(*pisrblk) & 0xfL);
#else
isrblk_ads.s = (unsigned)(((long)(*pisrblk) & 0xffff0L) >> 4L);
isrblk_ads.r = (unsigned)((long)(*pisrblk) & 0xfL);
#endif
#else
isrblk_ads.s = ds;
isrblk_ads.r = *pisrblk;
#endif
isrblk_ads.r++;
pcsetvec(intype,&isrblk_ads);
return(0);
}